package Singleton;


/**
 * @Author: Cjj
 * 双检锁/双重校验锁
 * 优点：线程安全，延迟加载，效率较高
 * 是否Lazy初始化：是
 * 是否多线程安全：是
 * 实现难度：较复杂
 * 这种方式采用双锁机制,安全且在多线程情况下能保持高性能
 * getinstance()的性能对应用程序很关键
 */
public class Singleton {
    private volatile static Singleton singleton;
    private Singleton (){}
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }


    /**
     * 登记式\静态内部类
     * 是否Lazy初始化：是
     * 是否多线程安全：是
     * 实现难度：一般
     * 描述：这种方式采用类装载的机制来保证初始化实例时只有一个线程，
      */
    public class SingletonHolder {
        private static class singletonHolder {
            private static final Singleton INSTANCE = new Singleton();
        }
        private SingletonHolder() {}
        public static final Singleton getInstance() {
            return singletonHolder.INSTANCE;
        }
    }

    /**
     * 枚举
     * 是否Lazy初始化：否
     * 是否多线程安全：是
     * 实现难度：易
     * 描述：这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制，
     *      绝对防止多次实例化。它不仅能避免多线程同步问题，而且还自动支持序列化机制，防止反序列化
     *      重新创建新的对象，绝对防止多次实例化。
     */
    public enum SingletonEnum {
        INSTANCE;
        public void doSomething() {
            //TODO
        }
    }

    /**
     * 经验之谈：一般情况下，不建议使用第 1 种和第 2 种懒汉方式，建议使用第 3 种饿汉方式。
     *只有在要明确实现 lazy loading 效果时，才会使用第 5 种登记方式。如果涉及到反序列化创建对象时，
     *可以尝试使用第 6 种枚举方式。如果有其他特殊的需求，可以考虑使用第 4 种双检锁方式。
     */
}
